home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1998 July / EnigmA AMIGA RUN 29 (1998)(G.R. Edizioni)(IT)[!][issue 1998-07 & 08].iso / recent / palmlink.lha / PalmLink / examples / PalmTransfer.c < prev   
C/C++ Source or Header  |  1998-06-21  |  21KB  |  867 lines

  1. /*********************************************************************
  2. **                                                                  **
  3. **        PalmTransfer    -- Data dialog between Amiga and Palm     **
  4. **                                                                  **
  5. *********************************************************************/
  6. /*
  7. **  Copyright © 1998 Richard Körber  --  All Rights Reserved
  8. **    E-Mail: shred@eratosthenes.starfleet.de
  9. **    URL:    http://shredzone.home.pages.de
  10. **
  11. ***************************************************************/
  12. /*
  13. **  This program is free software; you can redistribute it and/or modify
  14. **  it under the terms of the GNU General Public License as published by
  15. **  the Free Software Foundation; either version 2 of the License, or
  16. **  any later version.
  17. **
  18. **  This program is distributed in the hope that it will be useful,
  19. **  but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. **  GNU General Public License for more details.
  22. **
  23. **  You should have received a copy of the GNU General Public License
  24. **  along with this program; if not, write to the Free Software
  25. **  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26. **
  27. **  The author (Richard Körber) reserves the right to revoke the
  28. **  GNU General Public License whenever he feels that it is necessary,
  29. **  especially when he found out that the licence has been abused,
  30. **  ignored or violated, and without prior notice.
  31. **
  32. **  You must not use this source code to gain profit of any kind!
  33. **
  34. ***************************************************************/
  35. /*
  36. **  Compiles with SAS/C, e.g.
  37. **      sc PalmTransfer.c NOSTACKCHECK DATA=NEAR STRMER CPU=68060 OPT
  38. */
  39.  
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <clib/alib_protos.h>
  43. #include <clib/exec_protos.h>
  44. #include <clib/dos_protos.h>
  45. #include <clib/utility_protos.h>
  46. #include <clib/palmlink_protos.h>
  47. #include <pragmas/exec_pragmas.h>
  48. #include <pragmas/dos_pragmas.h>
  49. #include <pragmas/utility_pragmas.h>
  50. #include <pragmas/palmlink_pragmas.h>
  51. #include <exec/memory.h>
  52. #include <dos/dos.h>
  53. #include <dos/dosasl.h>
  54. #include <libraries/palmlink.h>
  55.  
  56.  
  57. #define  VERSIONSTR   "0.2ß"
  58. #define  DATESTR      "21.6.98"
  59. #define  COPYRIGHTSTR "1998"
  60. #define  EMAILSTR     "shred@eratosthenes.starfleet.de"
  61. #define  URLSTR       "http://shredzone.home.pages.de"
  62.  
  63. #define  NORMAL       "\2330m"
  64. #define  BOLD         "\2331m"
  65. #define  ITALIC       "\2333m"
  66. #define  UNDERLINE    "\2334m"
  67.  
  68. #define  MKTAG(a,b,c,d)  ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
  69.  
  70. static char ver[] = "$VER: PalmTransfer " VERSIONSTR " (" DATESTR ") " EMAILSTR;
  71. static char titletxt[] = \
  72.   BOLD "PalmTransfer " VERSIONSTR " (C) " COPYRIGHTSTR " Richard Körber -- all rights reserved" NORMAL "\n"
  73.   BOLD "  WARNING:" NORMAL " This is an early beta release. If you don't\n"
  74.   "    know what this means, do " BOLD "NOT" NORMAL " use this program!\n\n";
  75. static char helptxt[] = \
  76.   "  " ITALIC "E-Mail: " NORMAL EMAILSTR "\n"
  77.   "  " ITALIC "URL:    " NORMAL URLSTR "\n\n"
  78.   ITALIC "Usage:" NORMAL "\n"
  79.   "  BACKUP/S       Backup the database (DIR)\n"
  80.   "  RESTORE/S      Restore a backup (DIR)\n"
  81.   "  INSTALL/S      Install a file (FILE)\n"
  82.   "  MERGE/S        Merge a file (FILE)\n"
  83.   "  FETCH/S        Fetch a database (NAME)\n"
  84.   "  DELETE/S       Delete a database (NAME)\n"
  85.   "  LIST/S         List all databases\n"
  86.   "  PURGE/S        Purge deleted records\n"
  87.   "  DIR/K          Backup directory (if required)\n"
  88.   "  FILE/K         Filename (if required)\n"
  89.   "  NAME/K         Database name (if required)\n"
  90.   "  DEVICE/K       Serial device (\"serial.device\")\n"
  91.   "  UNIT/K/N       Serial unit (0)\n"
  92.   "  MAXBAUD/K/N    Maximum baud (28800)\n"
  93.   "\n";
  94.  
  95. struct Parameter
  96. {
  97.   LONG   backup;
  98.   LONG   restore;
  99.   LONG   install;
  100.   LONG   merge;
  101.   LONG   fetch;
  102.   LONG   delete;
  103.   LONG   list;
  104.   LONG   purge;
  105.   STRPTR dir;
  106.   STRPTR file;
  107.   STRPTR name;
  108.   STRPTR device;
  109.   LONG   *unit;
  110.   LONG   *maxbaud;
  111. }
  112. param;
  113.  
  114. static char template[] = "BACKUP/S,RESTORE/S,INSTALL/S,MERGE/S,FETCH/S,DELETE/S,LIST/S,PURGE/S,D=DIR/K,F=FILE/K,N=NAME/K,SD=DEVICE/K,SU=UNIT/K/N,SB=MAXBAUD/K/N";
  115.  
  116. struct FileNode
  117. {
  118.   struct Node Node;         // Backup/Restore
  119.   struct DateStamp Date;    // Backup only
  120.   struct DLP_DBInfo dbinfo; // Restore only
  121.   char FileName[108];       // Backup/Restore
  122. };
  123.  
  124. extern struct DOSBase *DOSBase;
  125. struct Library *PalmlinkBase;
  126. struct Library *UtilityBase;
  127. APTR socket = NULL;
  128. BOOL ignoreError = FALSE;
  129.  
  130.  
  131.  
  132. /*
  133. ** Open a connection to the Pilot
  134. */
  135. int Connect(void)
  136. {
  137.   LONG error;
  138.  
  139.   if(socket) return(TRUE);
  140.  
  141.   socket = PL_OpenSocketTags
  142.     (
  143.     PLTAG_ErrorPtr      , &error,
  144.     PLTAG_SerialDevice  , (param.device  ? param.device   : (unsigned char *)"serial.device"),
  145.     PLTAG_SerialUnit    , (param.unit    ? *param.unit    : 0),
  146.     PLTAG_SerialMaxRate , (param.maxbaud ? *param.maxbaud : 28800),
  147.     TAG_DONE
  148.     );
  149.  
  150.   if(socket)
  151.   {
  152.     Printf("Please press the HotSync button " ITALIC "now" NORMAL "\n");
  153.     return(PL_Accept(socket,10L));
  154.   }
  155.   else
  156.   {
  157.     Printf("** Socket error %ld\n",error);
  158.   }
  159.   return(FALSE);
  160. }
  161.  
  162. /*
  163. ** Close all databases and disconnect
  164. */
  165. void Disconnect(void)
  166. {
  167.   if(!socket) return;
  168.   DLP_AddSyncLogEntry(socket,"Synchronized with PalmLink\n-- AMIGA made it possible --\n");
  169.   DLP_EndOfSync(socket,0);
  170.   PL_CloseSocket(socket);
  171. }
  172.  
  173. /*
  174. ** Generate a AmigaDOS conformous file name from the
  175. ** DataBase name.
  176. */
  177. void genFileName(STRPTR name, struct DLP_DBInfo *dbinfo)
  178. {
  179.   UWORD i;
  180.  
  181.   strcpy(name,dbinfo->name);
  182.   for(i=0; i<strlen(name); i++)
  183.     if(name[i]<' ' || name[i]=='/' || name[i]==':') name[i]='_';  // Protect DOS characters
  184.   if(dbinfo->flags & DLPDBIF_RESOURCE)
  185.     strcat(name,".prc");
  186.   else
  187.     strcat(name,".pdb");
  188. }
  189.  
  190.  
  191. /*
  192. ** Convert a DLP_SysTime to a DOS DateStamp
  193. */
  194. void Date2Stamp(struct DLP_SysTime *time, struct DateStamp *ds)
  195. {
  196.   struct ClockData cld;
  197.   ULONG sec;
  198.  
  199.   cld.year  = time->year;
  200.   cld.month = time->month;
  201.   cld.mday  = time->day;
  202.   cld.hour  = time->hour;
  203.   cld.min   = time->minute;
  204.   cld.sec   = time->second;
  205.   sec = Date2Amiga(&cld);
  206.  
  207.   ds->ds_Tick   = (sec%60) * TICKS_PER_SECOND;
  208.   sec /= 60;
  209.   ds->ds_Minute = sec%(24*60);
  210.   sec /= 24*60;
  211.   ds->ds_Days   = sec;
  212. }
  213.  
  214. /*
  215. ** Convert a DOS DateStamp to DLP_SysTime
  216. */
  217. void Stamp2Date(struct DateStamp *ds, struct DLP_SysTime *time)
  218. {
  219.   struct ClockData cld;
  220.  
  221.   Amiga2Date(((ds->ds_Days*24*60)+ds->ds_Minute)*60+(ds->ds_Tick/TICKS_PER_SECOND),&cld);
  222.   time->year   = cld.year;
  223.   time->month  = cld.month;
  224.   time->day    = cld.mday;
  225.   time->hour   = cld.hour;
  226.   time->minute = cld.min;
  227.   time->second = cld.sec;
  228. }
  229.  
  230. /*
  231. ** Set a DLP_SysTime to the current date and time
  232. */
  233. void setToday(struct DLP_SysTime *time)
  234. {
  235.   struct DateStamp ds;
  236.   DateStamp(&ds);
  237.   Stamp2Date(&ds,time);
  238. }
  239.  
  240.  
  241. /*
  242. ** Set the Pilot into a synchronized state
  243. */
  244. void VoidSyncFlags(void)
  245. {
  246.   struct DLP_UserInfo user;
  247.   if(Connect())
  248.   {
  249.     if(DLP_GetUserInfo(socket,&user))
  250.     {
  251.       user.lastSyncPC = 0x00000000;     // Hopefully unique...
  252.       setToday(&user.successfulSync);
  253.       setToday(&user.lastSync);
  254.       DLP_SetUserInfo(socket,&user);
  255.     }
  256.   }
  257. }
  258.  
  259.  
  260. /*
  261. ** Backup a database
  262. */
  263. void cmd_backup(STRPTR dir)
  264. {
  265.   APTR fh;
  266.   BPTR lock;
  267.   BPTR olddir;
  268.   struct FileInfoBlock *fib;
  269.   struct List files;
  270.   struct FileNode *newnode;
  271.   struct FileNode *currEntry, *nextEntry;
  272.   struct DLP_DBInfo dbinfo;
  273.   struct DLP_SysTime time;
  274.   struct DateStamp stamp;
  275.  
  276.   UWORD i;
  277.   char filename[100];
  278.  
  279.   NewList(&files);
  280.  
  281.   if(!dir)
  282.   {
  283.     PutStr("** DIR required\n");
  284.     return;
  285.   }
  286.  
  287.   /* Check if existing, and if it is really a directory */
  288.   if(!(fib = AllocVec(sizeof(struct FileInfoBlock),MEMF_PUBLIC))) return;
  289.   lock = Lock(dir,ACCESS_READ);
  290.   if(!lock)                             // Does not exist, so create it
  291.   {
  292.     lock = CreateDir(dir);
  293.     if(!lock)                           // Couldn't create either
  294.     {
  295.       Printf("** Couldn't create directory %s\n",dir);
  296.       FreeVec(fib);
  297.       return;
  298.     }
  299.   }
  300.  
  301.   if(!Examine(lock,fib))
  302.   {
  303.     Printf("** Couldn't examine directory %s\n",dir);
  304.     goto error;
  305.   }
  306.   if(fib->fib_DirEntryType < 0)
  307.   {
  308.     Printf("** %s is not a directory\n",dir);
  309.     goto error;
  310.   }
  311.  
  312.   olddir = CurrentDir(lock);
  313.  
  314.   /* Read all file names into the files list */
  315.   while(ExNext(lock,fib))
  316.   {
  317.     if(fib->fib_DirEntryType > 0) continue;   // Skip subdirectories
  318.  
  319.     newnode = AllocVec(sizeof(struct FileNode),MEMF_ANY);
  320.     if(!newnode) goto error;
  321.  
  322.     CopyMem(fib->fib_FileName,newnode->FileName,108);
  323.     CopyMem(&fib->fib_Date,&newnode->Date,sizeof(struct DateStamp));
  324.     newnode->Node.ln_Name = newnode->FileName;
  325.     AddTail(&files,(struct Node *)newnode);
  326.   }
  327.  
  328.   /* Open conduit */
  329.   if(!Connect()) goto error;
  330.  
  331.   /* Backup all database entries */
  332.   for(i=0;;)
  333.   {
  334.     if(!DLP_OpenConduit(socket)) goto error;
  335.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_RAM,i,&dbinfo))    // get the next entry
  336.     {
  337.       if(PL_LastError(socket)==PLERR_NOTFOUND) break;     // last one
  338.       goto error;
  339.     }
  340.     i = dbinfo.index+1;
  341.     genFileName(filename,&dbinfo);
  342.     newnode = (struct FileNode *)FindName(&files,filename);   // search for the file
  343.     if(newnode)                                           // File does already exist
  344.     {
  345.       Stamp2Date(&newnode->Date,&time);                   // Check if the file has
  346.       if(  (time.year   == dbinfo.modifyDate.year)        // not been modified since
  347.          &&(time.month  == dbinfo.modifyDate.month)       // last backup
  348.          &&(time.day    == dbinfo.modifyDate.day)
  349.          &&(time.hour   == dbinfo.modifyDate.hour)
  350.          &&(time.minute == dbinfo.modifyDate.minute)
  351.          &&(time.second == dbinfo.modifyDate.second))
  352.       {
  353.         Printf("  Skipped: %s (not changed)\n",newnode->FileName);
  354.         Remove((struct Node *)newnode);                   // yes: skip it
  355.         FreeVec(newnode);
  356.         continue;
  357.       }
  358.     }
  359.  
  360.     /* Retrieve the file */
  361.     dbinfo.flags &= ~DLPDBIF_OPEN;                        // Saved database is not open
  362.  
  363.     fh = PL_FileOpen(filename,&dbinfo);
  364.     if(!fh)
  365.     {
  366.       Printf("** Unable to open file %s for writing\n",filename);
  367.       goto error;
  368.     }
  369.     Printf("  Store:   %s (from %s)... ",filename,dbinfo.name);
  370.     Flush(Output());
  371.     if(PL_FileRetrieve(fh,socket,0))                      // Get the file
  372.       PutStr("OK\n");
  373.     else
  374.       Printf("Failed (%ld)\n",PL_LastError(socket));
  375.     PL_FileClose(fh);
  376.  
  377.     Date2Stamp(&dbinfo.modifyDate,&stamp);                // Set file date to the
  378.     SetFileDate(filename,&stamp);                         // last modification date
  379.  
  380.     Remove((struct Node *)newnode);                       // Remove from list
  381.     FreeVec(newnode);
  382.   }
  383.  
  384.   /* Delete all remaining files */
  385.   for
  386.   (
  387.     currEntry=(struct FileNode *)files.lh_Head;
  388.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  389.     currEntry=nextEntry
  390.   )
  391.   {
  392.     Printf("  Delete:  %s...\n",currEntry->FileName);     // Is deleted on the Pilot too
  393.     Flush(Output());
  394.     if(DeleteFile(currEntry->FileName))
  395.       PutStr("OK\n");
  396.     else
  397.       Printf("Failed (%ld)\n",PL_LastError(socket));
  398.     Remove((struct Node *)currEntry);
  399.     FreeVec(currEntry);
  400.   }
  401.  
  402.   VoidSyncFlags();                                        // Sync done
  403.  
  404.   PutStr("Backup completed successfully\n");
  405.  
  406. error:
  407.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  408.   CurrentDir(olddir);
  409.   for                                                     // Clean up all memory
  410.   (
  411.     currEntry=(struct FileNode *)files.lh_Head;
  412.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  413.     currEntry=nextEntry
  414.   )
  415.   {
  416.     Remove((struct Node *)currEntry),
  417.     FreeVec(currEntry);
  418.   }
  419.   FreeVec(fib);                         // Release FIB
  420.   UnLock(lock);                         // Free directory lock
  421.   return;
  422. }
  423.  
  424. /*
  425. ** Restore a database
  426. */
  427. void cmd_restore(STRPTR dir)
  428. {
  429.   APTR fh;
  430.   BPTR lock;
  431.   BPTR olddir;
  432.   struct FileInfoBlock *fib;
  433.   struct List files;
  434.   struct FileNode *newnode;
  435.   struct FileNode *currEntry, *nextEntry;
  436.  
  437.   NewList(&files);
  438.  
  439.   if(!dir)
  440.   {
  441.     PutStr("** DIR required\n");
  442.     return;
  443.   }
  444.  
  445.   /* Check if existing, and if it is really a directory */
  446.   if(!(fib = AllocVec(sizeof(struct FileInfoBlock),MEMF_PUBLIC))) return;
  447.   lock = Lock(dir,ACCESS_READ);
  448.   if(!lock)                             // Does not exist
  449.   {
  450.     Printf("** Couldn't find directory %s\n",dir);
  451.     FreeVec(fib);
  452.     return;
  453.   }
  454.  
  455.   if(!Examine(lock,fib))
  456.   {
  457.     Printf("** Couldn't examine directory %s\n",dir);
  458.     goto error;
  459.   }
  460.   if(fib->fib_DirEntryType < 0)
  461.   {
  462.     Printf("** %s is not a directory\n",dir);
  463.     goto error;
  464.   }
  465.  
  466.   olddir = CurrentDir(lock);            // Set as current dir
  467.  
  468.   /* Read all file names into the files list */
  469.   while(ExNext(lock,fib))
  470.   {
  471.     if(fib->fib_DirEntryType > 0) continue;   // Skip subdirectories
  472.  
  473.     newnode = AllocVec(sizeof(struct FileNode),MEMF_ANY);
  474.     if(!newnode) goto error;
  475.  
  476.     CopyMem(fib->fib_FileName,newnode->FileName,108);
  477.     newnode->Node.ln_Name = newnode->FileName;
  478.     CopyMem(&fib->fib_Date,&newnode->Date,sizeof(struct DateStamp));
  479.  
  480.     fh = PL_FileOpen(newnode->FileName,NULL);
  481.     if(!fh)
  482.     {
  483.       Printf("** Unable to open file %s for reading\n",newnode->FileName);
  484.       goto error;
  485.     }
  486.     CopyMem(PL_FileGetDBInfo(fh),&newnode->dbinfo,sizeof(struct DLP_DBInfo));
  487.     PL_FileClose(fh);
  488.  
  489.     if(newnode->dbinfo.type == MKTAG('a','p','p','l'))
  490.       AddTail(&files,(struct Node *)newnode);         // send 'appl' as last
  491.     else
  492.       AddHead(&files,(struct Node *)newnode);
  493.   }
  494.  
  495.   /* Open connection */
  496.   if(!Connect()) goto error;
  497.  
  498.   /* Restore all database files */
  499.   for
  500.   (
  501.     currEntry=(struct FileNode *)files.lh_Head;
  502.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  503.     currEntry=nextEntry
  504.   )
  505.   {
  506.     if(!DLP_OpenConduit(socket)) goto error;
  507.     fh = PL_FileOpen(currEntry->FileName,NULL);
  508.     if(!fh)
  509.     {
  510.       Printf("** Unable to open file %s\n",currEntry->FileName);
  511.       goto error;
  512.     }
  513.     Printf("  Restore: %s as %s...",currEntry->FileName,currEntry->dbinfo.name);
  514.     Flush(Output());
  515.     if(PL_FileInstall(fh,socket,0))
  516.       PutStr("OK\n");
  517.     else
  518.       Printf("Failed (%ld)\n",PL_LastError(socket));
  519.     PL_FileClose(fh);
  520.     Remove((struct Node *)currEntry);
  521.     FreeVec(currEntry);
  522.   }
  523.  
  524.   PutStr("Restore completed successfully\n");
  525.   VoidSyncFlags();                                        // Sync done
  526.  
  527. error:
  528.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  529.   CurrentDir(olddir);
  530.   for                                                     // Clean up all memory
  531.   (
  532.     currEntry=(struct FileNode *)files.lh_Head;
  533.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  534.     currEntry=nextEntry
  535.   )
  536.   {
  537.     Remove((struct Node *)currEntry),
  538.     FreeVec(currEntry);
  539.   }
  540.   FreeVec(fib);                         // Release FIB
  541.   UnLock(lock);                         // Free directory lock
  542.   return;
  543. }
  544.  
  545.  
  546. /*
  547. ** Install a software
  548. */
  549. void cmd_install(STRPTR file)
  550. {
  551.   APTR fh;
  552.  
  553.   if(!file)
  554.   {
  555.     PutStr("** FILE required\n");
  556.     return;
  557.   }
  558.  
  559.   if(!Connect()) return;
  560.   if(!DLP_OpenConduit(socket)) return;
  561.  
  562.   fh = PL_FileOpen(file,NULL);
  563.   if(!fh)
  564.   {
  565.     Printf("** Unable to open file %s\n",file);
  566.     return;
  567.   }
  568.   Printf("Installing %s...",file);
  569.   Flush(Output());
  570.   if(PL_FileInstall(fh,socket,0))
  571.     PutStr("OK\n");
  572.   else
  573.     Printf("Failed (%ld)\n",PL_LastError(socket));
  574.  
  575.   PL_FileClose(fh);
  576.   VoidSyncFlags();
  577. }
  578.  
  579. /*
  580. ** Merge a software
  581. */
  582. void cmd_merge(STRPTR file)
  583. {
  584.   APTR fh;
  585.  
  586.   if(!file)
  587.   {
  588.     PutStr("** FILE required\n");
  589.     return;
  590.   }
  591.  
  592.   if(!Connect()) return;
  593.   if(!DLP_OpenConduit(socket)) return;
  594.  
  595.   fh = PL_FileOpen(file,NULL);
  596.   if(!fh)
  597.   {
  598.     Printf("** Unable to open file %s\n",file);
  599.     return;
  600.   }
  601.   Printf("Merging %s...",file);
  602.   Flush(Output());
  603.   if(PL_FileMerge(fh,socket,0))
  604.     PutStr("OK\n");
  605.   else
  606.     Printf("Failed (%ld)\n",PL_LastError(socket));
  607.  
  608.   PL_FileClose(fh);
  609.   VoidSyncFlags();
  610. }
  611.  
  612. /*
  613. ** Fetch a database
  614. */
  615. void cmd_fetch(STRPTR name)
  616. {
  617.   struct DLP_DBInfo dbinfo;
  618.   UWORD index;
  619.   BOOL found;
  620.   char filename[50];
  621.   APTR fh;
  622.  
  623.   if(!name)
  624.   {
  625.     PutStr("** NAME required\n");
  626.     return;
  627.   }
  628.  
  629.   if(!Connect()) return;
  630.   if(!DLP_OpenConduit(socket)) return;
  631.  
  632.   for(found=TRUE, index=0;;)
  633.   {
  634.     if(DLP_GetDBInfo(socket,0,DLPGDBF_RAM,index,&dbinfo))
  635.     {
  636.       if(!strcmp(name,dbinfo.name)) break;
  637.       index = dbinfo.index+1;
  638.     }
  639.     else
  640.     {
  641.       found=FALSE;
  642.       break;
  643.     }
  644.   }
  645.  
  646.   if(!found)
  647.     for(found=TRUE, index=0;;)
  648.     {
  649.       if(DLP_GetDBInfo(socket,0,DLPGDBF_ROM,index,&dbinfo))
  650.       {
  651.         if(!strcmp(name,dbinfo.name)) break;
  652.         index = dbinfo.index+1;
  653.       }
  654.       else
  655.       {
  656.         found=FALSE;
  657.         break;
  658.       }
  659.     }
  660.  
  661.   if(!found)
  662.   {
  663.     Printf("** Database %s not found\n",name);
  664.     return;
  665.   }
  666.  
  667.   genFileName(filename,&dbinfo);
  668.  
  669.   dbinfo.flags &= ~DLPDBIF_OPEN;      // Saved database is not open
  670.  
  671.   fh = PL_FileOpen(filename,&dbinfo);
  672.   if(!fh)
  673.   {
  674.     Printf("** Unable to open file %s\n",filename);
  675.     return;
  676.   }
  677.  
  678.   Printf("Fetching %s to file %s... ",name,filename);
  679.   Flush(Output());
  680.   if(PL_FileRetrieve(fh,socket,0))
  681.     PutStr("OK\n");
  682.   else
  683.     Printf("Failed (%ld)\n",PL_LastError(socket));
  684.  
  685.   PL_FileClose(fh);
  686. }
  687.  
  688. /*
  689. ** Delete a database
  690. */
  691. void cmd_delete(STRPTR name)
  692. {
  693.   struct DLP_DBInfo dbinfo = {0};
  694.   UWORD index;
  695.   BOOL found;
  696.  
  697.   if(!name)
  698.   {
  699.     PutStr("** NAME required\n");
  700.     return;
  701.   }
  702.  
  703.   if(!Connect()) return;
  704.   if(!DLP_OpenConduit(socket)) return;
  705.  
  706.   for(found=TRUE, index=0;;)
  707.   {
  708.     if(DLP_GetDBInfo(socket,0,DLPGDBF_RAM,index,&dbinfo))
  709.     {
  710.       if(!strcmp(name,dbinfo.name)) break;
  711.       index = dbinfo.index+1;
  712.     }
  713.     else
  714.     {
  715.       found=FALSE;
  716.       break;
  717.     }
  718.   }
  719.  
  720.   if(!found)
  721.   {
  722.     Printf("** Database %s not found\n",name);
  723.     return;
  724.   }
  725.  
  726.   Printf("Deleting %s... ",name);
  727.   Flush(Output());
  728.  
  729.   if(!DLP_DeleteDB(socket,0,name))
  730.   {
  731.     Printf("Failed (%ld)\n",PL_LastError(socket));
  732.     return;
  733.   }
  734.  
  735.   PutStr("OK\n");
  736.  
  737.   if(dbinfo.type==MKTAG('b','o','o','t')) PutStr("Rebooting after HotSync.\n");
  738. }
  739.  
  740. /*
  741. ** List all databases
  742. */
  743. void cmd_list(void)
  744. {
  745.   struct DLP_DBInfo info;
  746.   UWORD i;
  747.   ULONG nr;
  748.  
  749.   if(!Connect()) return;
  750.   if(!DLP_OpenConduit(socket)) return;
  751.  
  752.   PutStr(BOLD "-- LIST OF ALL RAM DATABASES --" NORMAL "\n");
  753.  
  754.   for(nr=1,i=0 ; ; nr++)
  755.   {
  756.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_RAM,i,&info)) break;
  757.     Printf("%3ld: '%s'\n",nr,info.name);
  758.     i = info.index+1;
  759.   }
  760.  
  761.   PutStr(BOLD "-- LIST OF ALL ROM DATABASES --" NORMAL "\n");
  762.  
  763.   for(nr=1,i=0 ; ; nr++)
  764.   {
  765.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_ROM,i,&info)) break;
  766.     Printf("%3ld: '%s'\n",nr,info.name);
  767.     i = info.index+1;
  768.   }
  769.  
  770.   PutStr(BOLD "---------------------------" NORMAL "\n");
  771.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  772. }
  773.  
  774. /*
  775. ** Purge all deleted records
  776. */
  777. void cmd_purge(void)
  778. {
  779.   struct DLP_DBInfo info;
  780.   UWORD i;
  781.   LONG dbh;
  782.  
  783.   if(!Connect()) return;
  784.   if(!DLP_OpenConduit(socket)) return;
  785.  
  786.   PutStr(BOLD "Purging deleted records from..." NORMAL "\n");
  787.  
  788.   for(i=0;;)
  789.   {
  790.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_RAM,i,&info)) break;
  791.     i = info.index+1;
  792.     if(info.flags & DLPDBIF_RESOURCE) continue;       // don't purge resources
  793.     Printf("  %s: ",info.name);
  794.     Flush(Output());
  795.     dbh = DLP_OpenDB(socket,0,DLPDBOF_READWRITE,info.name);
  796.     if(   dbh>=0
  797.        && DLP_CleanUpDatabase(socket,dbh)
  798.        && DLP_ResetSyncFlags(socket,dbh))
  799.     {
  800.       PutStr("OK\n");
  801.       DLP_CloseDB(socket,dbh);
  802.     }
  803.     else
  804.     {
  805.       Printf("Failed (%ld)\n",PL_LastError(socket));
  806.     }
  807.   }
  808.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  809.   VoidSyncFlags();
  810. }
  811.  
  812. /*
  813. ** MAIN PART
  814. */
  815. int main(void)
  816. {
  817.   struct RDArgs *args;
  818.  
  819.   PutStr(titletxt);
  820.  
  821.   if(args = (struct RDArgs *)ReadArgs(template,(LONG *)¶m,NULL))
  822.   {
  823.     if(UtilityBase = OpenLibrary("utility.library",36L))
  824.     {
  825.       if(PalmlinkBase = OpenLibrary("palmlink.library",0L))
  826.       {
  827.         if(param.backup)                  // BACKUP
  828.           cmd_backup(param.dir);
  829.         else if(param.restore)            // RESTORE
  830.           cmd_restore(param.dir);
  831.         else if(param.install)            // INSTALL
  832.           cmd_install(param.file);
  833.         else if(param.merge)              // MERGE
  834.           cmd_merge(param.file);
  835.         else if(param.fetch)              // FETCH
  836.           cmd_fetch(param.name);
  837.         else if(param.delete)             // DELETE
  838.           cmd_delete(param.name);
  839.         else if(param.list)               // LIST
  840.           cmd_list();
  841.         else if(param.purge)              // PURGE
  842.           cmd_purge();
  843.         else
  844.           PutStr(helptxt);                // No command was given
  845.  
  846.         if(socket)
  847.         {
  848.           if(!ignoreError && (PL_LastError(socket)!=0))
  849.             Printf("** Socket error code %ld\n",PL_LastError(socket));
  850.           Disconnect();
  851.         }
  852.         CloseLibrary(PalmlinkBase);
  853.       }
  854.       else PutStr("** Couldn't open palmlink.library\n");
  855.       CloseLibrary(UtilityBase);
  856.     }
  857.     else PutStr("** Couldn't open utility.library\n");
  858.  
  859.     FreeArgs(args);
  860.   }
  861.   else PutStr(helptxt);
  862.  
  863.   return(0);
  864. }
  865.  
  866. /********************************************************************/
  867.